/* * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ package org.springframework.xd.dirt.stream; import static org.springframework.xd.dirt.test.process.SingleNodeProcessingChainSupport.chain; import static org.springframework.xd.dirt.test.process.SingleNodeProcessingChainSupport.chainConsumer; import static org.springframework.xd.dirt.test.process.SingleNodeProcessingChainSupport.chainProducer; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.text.SimpleDateFormat; import java.util.Date; import org.joda.time.DateTime; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.xd.dirt.integration.bus.MessageBus; import org.springframework.xd.dirt.server.singlenode.SingleNodeApplication; import org.springframework.xd.dirt.server.TestApplicationBootstrap; import org.springframework.xd.dirt.test.SingleNodeIntegrationTestSupport; import org.springframework.xd.dirt.test.process.SingleNodeProcessingChain; import org.springframework.xd.dirt.test.process.SingleNodeProcessingChainConsumer; import org.springframework.xd.dirt.test.process.SingleNodeProcessingChainProducer; import org.springframework.xd.dirt.test.sink.NamedChannelSink; import org.springframework.xd.dirt.test.sink.SingleNodeNamedChannelSinkFactory; import org.springframework.xd.dirt.test.source.NamedChannelSource; import org.springframework.xd.dirt.test.source.SingleNodeNamedChannelSourceFactory; /** * What a Module/Stream developer might write to test a processing chain. * * @author David Turanski */ public class ExampleProcessingChainTests { private static SingleNodeApplication application; private static SingleNodeIntegrationTestSupport integrationSupport; private static int RECEIVE_TIMEOUT = 5000; @BeforeClass public static void setUp() { // Args not required. Just shown as an example. // Also, used to pick an unused port application = new TestApplicationBootstrap().getSingleNodeApplication().run("--transport", "local"); integrationSupport = new SingleNodeIntegrationTestSupport(application); } @Test public void testProcessingChain() { String processingChainUnderTest = "transform --expression='payload.toUpperCase()' | filter --expression='payload.length() > 4'"; String streamDefinition = "queue:producer >" + processingChainUnderTest + "> queue:consumer"; String streamName = "test"; StreamDefinition testStream = new StreamDefinition(streamName, streamDefinition); integrationSupport.createAndDeployStream(testStream); MessageBus messageBus = integrationSupport.messageBus(); NamedChannelSource source = new SingleNodeNamedChannelSourceFactory(messageBus).createNamedChannelSource("queue:producer"); NamedChannelSink sink = new SingleNodeNamedChannelSinkFactory(messageBus).createNamedChannelSink("queue:consumer"); source.sendPayload("hello"); String result = (String) sink.receivePayload(RECEIVE_TIMEOUT); assertEquals("HELLO", result); source.sendPayload("a"); result = (String) sink.receivePayload(RECEIVE_TIMEOUT); assertNull(result); source.unbind(); sink.unbind(); assertTrue("stream " + testStream.getName() + "not undeployed", integrationSupport.undeployAndDestroyStream(testStream)); } /** * Test a simple processing chain by sending and receiving payloads. */ @Test public void processingChain() { String processingChainUnderTest = "transform --expression='payload.toUpperCase()' | filter --expression='payload.length() > 4'"; SingleNodeProcessingChain chain = chain(application, "eezypeasy", processingChainUnderTest); chain.sendPayload("hello"); String result = (String) chain.receivePayload(RECEIVE_TIMEOUT); assertEquals("HELLO", result); chain.sendPayload("a"); result = (String) chain.receivePayload(RECEIVE_TIMEOUT); assertNull(result); chain.destroy(); } /** * Test a processing chain that provides a source. Verify the result. */ @Test public void chainWithSource() { String processingChainUnderTest = "time | transform --expression='T(org.joda.time.format.DateTimeFormat).forPattern(\"yyyy-MM-dd HH:mm:ss\").parseDateTime(payload)'"; SingleNodeProcessingChainConsumer chain = chainConsumer(application, "dateToDateTime", processingChainUnderTest); Object payload = chain.receivePayload(RECEIVE_TIMEOUT); assertTrue(payload instanceof DateTime); chain.destroy(); } /** * Test a processing chain that provides a sink. Send a payload and set up a tap to verify the result; */ @Test public void chainWithSink() { String processingChainUnderTest = "transform --expression='T(org.joda.time.format.DateTimeFormat).forPattern(\"yyyy-MM-dd HH:mm:ss\").parseDateTime(payload)' | log"; SingleNodeProcessingChainProducer chain = chainProducer(application, "dateToDateTime", processingChainUnderTest); StreamDefinition tap = new StreamDefinition("testtap", "tap:stream:dateToDateTime.0 > queue:tap"); integrationSupport.createAndDeployStream(tap); NamedChannelSink sink = new SingleNodeNamedChannelSinkFactory(integrationSupport.messageBus()).createNamedChannelSink("queue:tap"); chain.sendPayload(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); Object payload = sink.receivePayload(RECEIVE_TIMEOUT); assertNotNull(payload); assertTrue(payload instanceof DateTime); integrationSupport.undeployAndDestroyStream(tap); chain.destroy(); } @AfterClass public static void tearDown() { if (application != null) { application.close(); } } }